package io.xmu.dataanalysis.data.analysis;

import com.google.common.collect.HashMultiset;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Multiset;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;
import java.util.Map;

import io.xmu.dataanalysis.data.BaseDataCache;
import io.xmu.dataanalysis.data.DataService;
import io.xmu.dataanalysis.data.OrderStatus;
import io.xmu.dataanalysis.data.PageType;
import io.xmu.dataanalysis.entity.Favorite;
import io.xmu.dataanalysis.entity.Goods;
import io.xmu.dataanalysis.entity.GoodsDailyData;
import io.xmu.dataanalysis.entity.Order;
import io.xmu.dataanalysis.entity.PV;
import io.xmu.dataanalysis.entity.ShoppingCart;
import io.xmu.dataanalysis.repository.GoodsDailyDataRepo;
import io.xmu.dataanalysis.repository.ShoppingCartRepo;
import io.xmu.dataanalysis.util.DateUtils;

/**
 * @author lepdou 2017-03-12
 */
@Component
public class GoodsDataAnalysis {

  @Autowired
  private ShoppingCartRepo shoppingCartRepo;
  @Autowired
  private BaseDataCache baseDataCache;
  @Autowired
  private GoodsDailyDataRepo goodsDailyDataRepo;

  @Autowired
  private DataService dataService;


  @Transactional
  public void analysis(String partition) {
    goodsDailyDataRepo.deleteByPartition(partition);

    analysisFavorite(partition);
    analysisOrder(partition);
    analysisPV(partition);
    analysisCart(partition);
  }

  private void analysisFavorite(String partition) {
    Iterable<Favorite> favorites = dataService.getFavoriteByPartition(partition);

    Multiset<Integer> favoriteCounter = HashMultiset.create();
    for (Favorite favorite : favorites) {
      favoriteCounter.add(favorite.getGoodsId());
    }

    List<GoodsDailyData> goodsDailyDatas = Lists.newLinkedList();
    for (Integer goodsId : favoriteCounter.elementSet()) {

      GoodsDailyData goodsDailyData = getOrCreate(goodsId, partition);

      goodsDailyData.setFavoriteCount(favoriteCounter.count(goodsId));
      goodsDailyDatas.add(goodsDailyData);
    }

    goodsDailyDataRepo.save(goodsDailyDatas);
  }

  private void analysisCart(String partition) {
    Date startDate = DateUtils.getDateBeginTime(partition);
    Date endDate = DateUtils.getDateEndTime(partition);

    Iterable<ShoppingCart>
        shoppingCarts =
        shoppingCartRepo.findByCreateTimeAfterAndCreateTimeBefore(startDate, endDate);

    Multiset<Integer> counter = HashMultiset.create();
    for (ShoppingCart shoppingCart : shoppingCarts) {
      counter.add(shoppingCart.getGoodsId());
    }

    List<GoodsDailyData> goodsDailyDatas = Lists.newLinkedList();
    for (Integer goodsId : counter.elementSet()) {

      GoodsDailyData goodsDailyData = getOrCreate(goodsId, partition);

      goodsDailyData.setAddToCartCount(counter.count(goodsId));
      goodsDailyDatas.add(goodsDailyData);
    }

    goodsDailyDataRepo.save(goodsDailyDatas);
  }

  private void analysisOrder(String partition) {
    Iterable<Order> orders = dataService.getOrderByPartition(partition);

    Map<Integer, Long> payMoneyCounter = Maps.newHashMap();
    Multiset<Integer> counter = HashMultiset.create();
    for (Order order : orders) {
      if (!OrderStatus.isSuccessOrder(order.getStatus())) {
        continue;
      }

      int goodsId = order.getGoodsId();
      Goods goods = baseDataCache.getGoods(goodsId);
      if (goods == null) {
        continue;
      }
      counter.add(goodsId);

      Long moneyCount = payMoneyCounter.get(goodsId);
      if (moneyCount == null) {
        moneyCount = 0L;
      }

      moneyCount += goods.getPrice();
      payMoneyCounter.put(goodsId, moneyCount);
    }

    List<GoodsDailyData> goodsDailyDatas = Lists.newLinkedList();
    for (Integer goodsId : counter.elementSet()) {

      GoodsDailyData goodsDailyData = getOrCreate(goodsId, partition);

      goodsDailyData.setPayCount(counter.count(goodsId));
      goodsDailyData.setPayMoneyCount(payMoneyCounter.get(goodsId));
      goodsDailyDatas.add(goodsDailyData);
    }

    goodsDailyDataRepo.save(goodsDailyDatas);
  }

  private void analysisPV(String partition) {
    Iterable<PV> pvs = dataService.getPVByTypeAndPartition(PageType.GOODS.value(), partition);

    Multiset<Integer> counter = HashMultiset.create();
    for (PV pv : pvs) {
      counter.add(pv.getGoodsId());
    }

    List<GoodsDailyData> goodsDailyDatas = Lists.newLinkedList();
    for (Integer goodsId : counter.elementSet()) {

      GoodsDailyData goodsDailyData = getOrCreate(goodsId, partition);

      goodsDailyData.setPv(counter.count(goodsId));
      goodsDailyDatas.add(goodsDailyData);
    }

    goodsDailyDataRepo.save(goodsDailyDatas);
  }

  private GoodsDailyData getOrCreate(int goodsId, String partition) {
    Goods goods = baseDataCache.getGoods(goodsId);
    if (goods == null) {
      goods = baseDataCache.randomGoods();
    }

    GoodsDailyData goodsDailyData = goodsDailyDataRepo.findByGoodsIdAndPartition(goodsId, partition);

    if (goodsDailyData == null) {
      goodsDailyData = new GoodsDailyData();
      goodsDailyData.setGoodsId(goodsId);
      goodsDailyData.setPartition(partition);
      int shopId = goods.getShopId();
      goodsDailyData.setShopId(shopId);
      goodsDailyData.setCateId(baseDataCache.getShop(shopId).getCateId());
    }

    return goodsDailyData;
  }


}
